#include "thttpd.h"

modbus_t *m;

void *handler1(void *arg);
void *handler2(void *arg);
struct std_node *share();
int handle_msgqueue1(void);
struct msgbuf msgque; //消息队列传值  增加了num1 == 1  msgque.mum2 代表点击输入

int msgid;
int main(int argc, char const *argv[])
{
    struct std_node *p = NULL;
    pthread_t tid1, tid2;
    m = modbus_new_tcp("192.168.50.127", 502); //tcp的库  用windows的ip  设备也是
    modbus_set_slave(m, 1);
    modbus_connect(m);
    p = share(); //共享内存
    msgid = handle_msgqueue1();
    pthread_create(&tid1, NULL, handler1, p); //把东西加入到共享内存中了  //采集
    printf("-------%s----%s----%d----\n", __FILE__, __func__, __LINE__);
    pthread_create(&tid2, NULL, handler2, &msgid); //控制
    printf("-------%s----%s----%d----\n", __FILE__, __func__, __LINE__);
    pthread_join(tid1, 0);
    pthread_join(tid2, 0);

    modbus_close(m);
    modbus_free(m);
    return 0;
}

// 函数用于从Modbus设备读取浮点数  
float read_float_from_modbus(uint16_t address) {  
    uint16_t tab_reg[2]; // 用于存储两个16位寄存器的数组  
    int rc; 
    // 读取两个寄存器  
    rc = modbus_read_registers(m, address, 2, tab_reg);  
    if (rc != 2) {  
        fprintf(stderr, "Failed to read registers: %s\n", modbus_strerror(errno));  
        
        return 0.0f; // 或者其他错误处理  
    }
    
    // 组合两个16位值为一个32位整数  
    uint32_t value = (tab_reg[0] << 16) | tab_reg[1];  
  
    // 注意：这里假设Modbus设备和你的系统使用相同的字节序。  
    // 如果不是，你可能需要使用某种形式的字节序转换（例如，bswap32）  
  
    // 将32位整数转换为浮点数  
    float float_value = *(float*)&value;  
  
    return float_value;  
}  

void *handler1(void *arg)
{ //03
    uint16_t dest[10] = {0};  //保持寄存器
    uint8_t destC[2]={0};    //线圈
    struct std_node *p = (struct std_node *)arg;  
    struct std_node *end = p + (7 *sizeof(struct std_node)); // 计算共享内存的末尾  
    int num_registers_to_read = 7; // 只需要读取dest[1]、dest[3]、dest[5]，共3个寄存器  
    while (1) {  
        int i = 0;  
        // 每次循环只处理一个 std_node  
        while (i < num_registers_to_read && p < end) {  
             // 读取寄存器
            int register_index = i * 2 + 1; // 因为只需要读取奇数索引的寄存器
            // 更新 std_node 的值
            // 假设我们只关心 i_val，所以将读取的值转换为 int 并存储
            if (i==0)
            {
                int devnum=modbus_read_registers(m, 40000 + register_index, 1, &dest[register_index]);
                if (devnum <= -1)
                {
                    p->ret=0;                                 //采集失败
                }else
                {
                    p->ret=1;                                 //采集成功
                }
                p->key=101+i;                             //key=101;
                p->type=2;
                p->old_val.i_val = p->new_val.i_val;     // 更新旧值为当前新值
                p->new_val.i_val = dest[register_index]; // 更新新值
                printf("Device %d: new_val:%d  old_val:%d  node_key:%d\n", (register_index - 1) / 2 + 1, p->new_val.i_val, p->old_val.i_val,p->key);     //打印出啦
                printf("type:%d\n",p->type);
            }else if (i==1 || i==2) 
            {
                p->key=101+i;                             //key= 102  103               
                p->old_val.f_val = p->new_val.f_val;     // 更新旧值为当前新值
                p->new_val.f_val = read_float_from_modbus(40000 +register_index); // 更新新值
               if (p->new_val.f_val != 0.0f)                
                {
                    p->ret=1;                                 //采集成功
                }else
                {
                    p->ret=0;                                 //采集失败
                }
                p->type=3;
                // 输出变化（如果需要）
            printf("Device %d: new_val:%.2f old_val:%.2f node_key:%d\n", (register_index - 1) / 2 + 1, p->new_val.f_val, p->old_val.f_val,p->key); //打印出啦
            }else
            {
                //读线圈  m  地址  存放位置  i=3
                // modbus_read_registers(m,, 1, &dest[register_index]);
                int devnum=modbus_read_bits(m,i-2,1,destC);
                if (devnum!=1)                            //ret
                {
                    p->ret=0;
                }else
                {
                    p->ret=1;
                }
                p->key=101+i;                             //key=104 105 106 107
                p->old_val.i_val = p->new_val.i_val;     // 更新旧值为当前新值
                p->new_val.i_val = destC[0]; // 更新新值
                p->type=1;
                printf("dest[0]:%d\n",destC[0]);
                printf("Device %d: new_val:%d  old_val:%d  node_key:%d\n", (register_index - 1) / 2 + 1, p->new_val.i_val, p->old_val.i_val,p->key);     //打印出啦  
            }
            // 移动到下一个 std_node  
            p++;  
            i++;  
        }
        // 如果已经处理完所有要读取的寄存器或到达共享内存的末尾，重置 p 指针  
        if (i >= num_registers_to_read) {  
            p = (struct std_node *)arg; // 重置为共享内存的起始位置  
        }  
  
        sleep(5); // 等待3秒  
    }  
  
    pthread_exit(NULL);
}
void *handler2(void *arg)
{
    // 05
    msgid = *(int *)arg;
    printf("handler2 msgid: %d", msgid);
    int addr;
    printf("\ndian:%d %ld %d \n", msgque.key, msgque.type,msgque.val.b_val);
    while (1)
    {
        //没读出来,因为消息队列中没有放数据,所以没读出来
        // msg_queue_recv("msg",&msgque,sizeof(msgque),10,0);//1:表示读取消息类型为1的第一个消息， 如果为0表示读取消息队列中的第一个消息
        msgrcv(msgid, &msgque, sizeof(msgque) - sizeof(long), 10, 0); //1:表示读取消息类型为1的第一个消息， 如果为0表示读取消息队列中的第一个消息
        printf("hou:%d %ld %d \n", msgque.key, msgque.type,msgque.val.b_val);      
        if (msgque.type == 10)
        {
            printf("hou:%d %ld %d \n", msgque.key, msgque.type,msgque.val.b_val);
            if (msgque.key==104 && msgque.val.b_val==1)
            {
                addr=1;
                printf("hou:%d %ld %d \n", msgque.key, msgque.type,msgque.val.b_val);
                printf("通风扇打开\n");
            }
            else if (msgque.key==104 && msgque.val.b_val==0)
            {
                addr=1;
                printf("通风扇关闭\n");
            }
            else if (msgque.key==105 && msgque.val.b_val==1)
            {
                addr=2;
                printf("灯打开\n");
            }
            else if (msgque.key==105 && msgque.val.b_val==0)
            {
                addr=2;
                printf("灯关闭\n");
            }

            if (msgque.key==106 && msgque.val.b_val==1)
            {
                addr=3;
                printf("阀门打开\n");
            }
            else if (msgque.key==106 && msgque.val.b_val==0)
            {
                addr=3;
                printf("阀门关闭\n");
            }
            else if (msgque.key==107 && msgque.val.b_val==1)
            {
                addr=4;
                printf("报警器打开\n");
            }
            else if (msgque.key==107 && msgque.val.b_val==0)
            {
                addr=4;
                printf("报警器关闭\n");
            }
           
            modbus_write_bit(m, addr,msgque.val.b_val);  //获取地址与开关状态
        }
        else
        {
            msgque.type == 0;
            msgsnd(msgid, &msgque, sizeof(msgque) - sizeof(long), 0); //写入msg中
        }
        sleep(2);  //防抖
    }
    return NULL;
}
struct std_node *share()
{
    struct shm_param param;
    int shmid;
    int *num = NULL;
    struct std_node *p = NULL;
    //创建或者打开共享内存
    shmid = shm_init(&param, "shm.txt", sizeof(param)); //大小我
    char reply_buf[HTML_SIZE] = {0};
    if (shmid < 0)
    {
        perror("shm init err\n");
        return NULL;
    }
    printf("共享内存 :shmid: %d\n", shmid);
    //映射共享内存
    num = shm_getaddr(&param);
    p = (struct std_node *)(num + 1);
    p = (struct std_node *)(p + 5);   //偏移量  stm32的是前5个
    if (p == NULL)
    {
        perror("shmat get arr err\n");
        return NULL;
    }
    return p;
}

// 消息队列
// int handle_msgqueue1(void)
// {
//     int msgid;
//     struct msgbuf msg;
//     msgid=msg_queue_send("msg",&msg,sizeof(msg),0);
//     if (msgid <=0)
//     {
//         perror("Failed to send message");
//     }
//     printf("消息队列 msgid: %d\n", msgid);
//     return msgid;
// }
//消息队列
int handle_msgqueue1(void)
{
    key_t key;
    int msgid;
    if ((key = ftok("/mnt/msg.txt", 'b')) < 0)
    {
        perror("queue ftok err");
        return -1;
    }
    printf("key = %#x\n", key);

    //打开或创建消息队列
    msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666); //创建消息队列，如果之前有就返回-1
    if (msgid <= 0)
    {
        if (errno == EEXIST)
            msgid = msgget(key, 0666); //直接打开消息队列
        else
        {
            perror("msgget err");
            return -1;
        }
    }
    printf("消息队列:msgid: %d\n", msgid);
    return msgid;
}
